package ru.amse.tsyganov.jumleditor.view;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

import ru.amse.tsyganov.jumleditor.model.ActivityGraph;
import ru.amse.tsyganov.jumleditor.model.Partition;
import ru.amse.tsyganov.jumleditor.model.State;
import ru.amse.tsyganov.jumleditor.model.Transition;
import ru.amse.tsyganov.jumleditor.properties.PropertiesList;
import ru.amse.tsyganov.jumleditor.properties.StringProperty;

public class ActivityGraphView<T extends ActivityGraph> extends ViewElement<T> {
	
	private static final int PRECISION_OF_SELECTION = 10;
	
	private final ModelViewMap modelViewMap = new ModelViewMap();
	
	private final SelectedItems selectedItems = new SelectedItems();
	
	public ActivityGraphView(T model) {
		super(model);
	}

	@Override
	public void accept(Visitor v) {
		v.visitActivityGraphView(this);
		
		for (Partition p : getModel().getPartitions()) {
			PartitionView<Partition> partitionView = 
				modelViewMap.getPartitionsMap().get(p);
			partitionView.accept(v);
		}
	}

	@Override
	public void paint(GC gc) {
		assert gc != null;
		
		gc.setAntialias(SWT.ON);
		gc.setFont(Fonts.getDefaultFont());
		
		for (StateView<? extends State> s : getModelViewMap().
				getStatesMap().values()) {
			
			s.prepaintEvent(gc);
		}
				
		for (Partition p : getModel().getPartitions()) {
			PartitionView<Partition> partitionView = 
				modelViewMap.getPartitionsMap().get(p);
			partitionView.paint(gc);
		}
		
		paintActivePoints(gc);
	}

	@Override
	public List<? extends ActivePoint> getActivePoints() {
		throw new UnsupportedOperationException();
	}
	
	@Override
	public ModelViewMap getModelViewMap() {
		return modelViewMap;
	}
	
	@Override
	public SelectedItems getSelectedItems() {
		return selectedItems;
	}

	@Override
	public ActivityGraphView<T> getActivityGraphView() {
		return this;
	}
	
	public StateView<? extends State> getStateView(int x, int y) {
		
		for (Partition p : getModel().getPartitions()) {
			for (State s : p.getContents()) {
				StateView<? extends State> stateView = 
					getModelViewMap().getStatesMap().get(s);
				if (stateView.getRectangle().contains(x, y)) {
					return stateView;
				}
			}
		}
		return null;
	}
	
	public TransitionView<? extends Transition> getTransitionView(int x, int y) {
		
		for (Partition p : getModel().getPartitions()) {
			for (State s : p.getContents()) {
				for (Transition t : s.getStateVertex().getOutgoing()) {
					
					State source = t.getSource().getContainer();
					State target = t.getTarget().getContainer();

					StateView<? extends State> sourceStateView = 
						getModelViewMap().getStatesMap().get(source);

					StateView<? extends State> targetStateView = 
						getModelViewMap().getStatesMap().get(target);

					int x0 = sourceStateView.getCenterPoint().x;
					int y0 = sourceStateView.getCenterPoint().y;

					int x1 = targetStateView.getCenterPoint().x;
					int y1 = targetStateView.getCenterPoint().y;

					double d = Math.abs(((y0 - y1) * x + (x1 - x0) * y + 
							(x0	* y1 - x1 * y0)) / Math.sqrt(
									Math.pow(x1 - x0, 2) + Math.pow(y1 - y0, 2)));

					if (x0 > x1) {
						int b = x0;
						x0 = x1;
						x1 = b;
					}

					if (y0 > y1) {
						int b = y0;
						y0 = y1;
						y1 = b;
					}

					if (x >= (x0 - PRECISION_OF_SELECTION) && 
							x <= (x1 + PRECISION_OF_SELECTION) && 
							y >= (y0 - PRECISION_OF_SELECTION) && 
							y <= (y1 + PRECISION_OF_SELECTION)) {
						
						if (d < PRECISION_OF_SELECTION) {
							return getModelViewMap().getTransitionsMap().get(t);
						}
					}
				}
			}
		}
		return null;
	}
	
	public ActivePoint getActivePoint(int x, int y) {
		
		for (Partition p : getModel().getPartitions()) {
			for (State s : p.getContents()) {
				
				StateView<? extends State> stateView = 
					getModelViewMap().getStatesMap().get(s);

				for (ActivePoint point : stateView.getActivePoints()) {
					if (point.getRectangle().contains(x, y)) {
						return point;
					}
				}

				for (Transition t : s.getStateVertex().getOutgoing()) {
					TransitionView<? extends Transition> transitionView = 
						getModelViewMap().getTransitionsMap().get(t);
					
					for (ActivePoint point : transitionView.getActivePoints()) {
						if (point.getRectangle().contains(x, y)) {
							return point;
						}
					}
				}
			}
		}
		return null;
	}

	@Override
	public void paintActivePoints(GC gc) {
		for (StateView<? extends State> s : 
			getSelectedItems().getSelectedStates()) {
			
			s.paintActivePoints(gc);
		}
		
		for (TransitionView<? extends Transition> t : 
			getSelectedItems().getSelectedTransitions()) {
			
			t.paintActivePoints(gc);
		}
	}
	
	@Override
	public PropertiesList getProperties() {
		throw new UnsupportedOperationException();
	}

	@Override
	public StringProperty getMainProperty() {
		throw new UnsupportedOperationException();
	}

	@Override
	public Point getCenterPoint() {
		throw new UnsupportedOperationException();
	}
}
